// import java.util.Calendar;
#include "SQLIntervalUnit.h"

#include "../../../utils/StringUtils.h"
#include "../../../utils/log.h"
#include "../../../utils/BOOL.h"
// #include <boost/date_time/posix_time/posix_time.hpp>

SQLIntervalUnit SQLIntervalUnit::YEAR = SQLIntervalUnit(1 << 0, make_string_ptr("YEAR"));
SQLIntervalUnit SQLIntervalUnit::YEAR_MONTH = SQLIntervalUnit(1 << 1, make_string_ptr("YEAR_MONTH"));
SQLIntervalUnit SQLIntervalUnit::QUARTER = SQLIntervalUnit(1 << 2, make_string_ptr("QUARTER"));
SQLIntervalUnit SQLIntervalUnit::MONTH = SQLIntervalUnit(1 << 3, make_string_ptr("MONTH"));
SQLIntervalUnit SQLIntervalUnit::WEEK = SQLIntervalUnit(1 << 4, make_string_ptr("WEEK"));
SQLIntervalUnit SQLIntervalUnit::DAY = SQLIntervalUnit(1 << 5, make_string_ptr("DAY"));
SQLIntervalUnit SQLIntervalUnit::DAY_HOUR = SQLIntervalUnit(1 << 6, make_string_ptr("DAY_HOUR"));
SQLIntervalUnit SQLIntervalUnit::DAY_MINUTE = SQLIntervalUnit(1 << 7, make_string_ptr("DAY_MINUTE"));
SQLIntervalUnit SQLIntervalUnit::DAY_SECOND = SQLIntervalUnit(1 << 8, make_string_ptr("DAY_SECOND"));
SQLIntervalUnit SQLIntervalUnit::DAY_MICROSECOND = SQLIntervalUnit(1 << 9, make_string_ptr("DAY_MICROSECOND"));
SQLIntervalUnit SQLIntervalUnit::HOUR = SQLIntervalUnit(1 << 10, make_string_ptr("HOUR"));
SQLIntervalUnit SQLIntervalUnit::HOUR_MINUTE = SQLIntervalUnit(1 << 11, make_string_ptr("HOUR_MINUTE"));
SQLIntervalUnit SQLIntervalUnit::HOUR_SECOND = SQLIntervalUnit(1 << 12, make_string_ptr("HOUR_SECOND"));
SQLIntervalUnit SQLIntervalUnit::HOUR_MICROSECOND = SQLIntervalUnit(1 << 13, make_string_ptr("HOUR_MICROSECOND"));
SQLIntervalUnit SQLIntervalUnit::MINUTE = SQLIntervalUnit(1 << 14, make_string_ptr("MINUTE"));
SQLIntervalUnit SQLIntervalUnit::MINUTE_SECOND = SQLIntervalUnit(1 << 15, make_string_ptr("MINUTE_SECOND"));
SQLIntervalUnit SQLIntervalUnit::MINUTE_MICROSECOND = SQLIntervalUnit(1 << 16, make_string_ptr("MINUTE_MICROSECOND"));
SQLIntervalUnit SQLIntervalUnit::SECOND = SQLIntervalUnit(1 << 17, make_string_ptr("SECOND"));
SQLIntervalUnit SQLIntervalUnit::SECOND_MICROSECOND = SQLIntervalUnit(1 << 18, make_string_ptr("SECOND_MICROSECOND"));
SQLIntervalUnit SQLIntervalUnit::MICROSECOND = SQLIntervalUnit(1 << 19, make_string_ptr("MICROSECOND"));
SQLIntervalUnit SQLIntervalUnit::DAY_OF_WEEK = SQLIntervalUnit(1 << 20, make_string_ptr("DAY_OF_WEEK"));
SQLIntervalUnit SQLIntervalUnit::DOW = SQLIntervalUnit(1 << 21, make_string_ptr("DOW"));
SQLIntervalUnit SQLIntervalUnit::DAY_OF_MONTH = SQLIntervalUnit(1 << 22, make_string_ptr("DAY_OF_MONTH"));
SQLIntervalUnit SQLIntervalUnit::DAY_OF_YEAR = SQLIntervalUnit(1 << 23, make_string_ptr("DAY_OF_YEAR"));
SQLIntervalUnit SQLIntervalUnit::YEAR_OF_WEEK = SQLIntervalUnit(1 << 24, make_string_ptr("YEAR_OF_WEEK"));
SQLIntervalUnit SQLIntervalUnit::YOW = SQLIntervalUnit(1 << 25, make_string_ptr("YOW"));
SQLIntervalUnit SQLIntervalUnit::TIMEZONE_HOUR = SQLIntervalUnit(1 << 26, make_string_ptr("TIMEZONE_HOUR"));
SQLIntervalUnit SQLIntervalUnit::TIMEZONE_MINUTE = SQLIntervalUnit(1 << 27, make_string_ptr("TIMEZONE_MINUTE"));
SQLIntervalUnit SQLIntervalUnit::DOY = SQLIntervalUnit(1 << 28, make_string_ptr("DOY"));
SQLIntervalUnit SQLIntervalUnit::YEAR_TO_MONTH = SQLIntervalUnit(1 << 29, make_string_ptr("YEAR_TO_MONTH")); // ("YEAR TO MONTH")

SQLIntervalUnit::SQLIntervalUnit(uint64_t mask, string_ptr name_)
{
  this->name = name_;
  // LOG_INFO << "name:" << name_->c_str();
  this->nameLCase = StringUtils::toLower(name_);
  this->mask = mask;
}

SQLIntervalUnit::SQLIntervalUnit(SQLIntervalUnit *sqlIntervalUnit)
{
  this->name = sqlIntervalUnit->name;
  LOG_INFO << "name:" << this->name->c_str();
  this->nameLCase = StringUtils::toLower(this->name);
  this->mask = sqlIntervalUnit->mask;
}

SQLIntervalUnit::SQLIntervalUnit()
{
  // this->name = name();
  // this->nameLCase = name.toLowerCase();
}

BOOL_ptr SQLIntervalUnit::add(std::chrono::system_clock::time_point &calendar, int intervalInt, SQLIntervalUnit unit)
{
  // switch (unit) {
  if (unit.mask == YEAR.mask)
  {
    // calendar.add(Calendar.YEAR, intervalInt);
    // calendar = calendar + boost::gregorian::years(intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == MONTH.mask)
  {
    // calendar.add(Calendar.MONTH, intervalInt);
    // calendar = calendar + boost::gregorian::months(intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == WEEK.mask)
  {
    // calendar.add(Calendar.WEEK_OF_MONTH, intervalInt);
    calendar = calendar + std::chrono::hours(7 * 24 * intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == DAY.mask)
  {
    // calendar.add(Calendar.DAY_OF_MONTH, intervalInt);
    calendar = calendar + std::chrono::hours(24 * intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == HOUR.mask)
  {
    // calendar.add(Calendar.HOUR_OF_DAY, intervalInt);
    calendar = calendar + std::chrono::hours(intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == MINUTE.mask)
  {
    // calendar.add(Calendar.MINUTE, intervalInt);
    calendar = calendar + std::chrono::minutes(intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == SECOND.mask)
  {
    // calendar.add(Calendar.SECOND, intervalInt);
    calendar = calendar + std::chrono::seconds(intervalInt);
    return BOOL::TRUE;
  }
  else if (unit.mask == MICROSECOND.mask)
  {
    // calendar.add(Calendar.MILLISECOND, intervalInt);
    calendar = calendar + std::chrono::milliseconds(intervalInt);
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

BOOL_ptr SQLIntervalUnit::isDateTime()
{
  if (this->mask == HOUR.mask ||
      this->mask == MINUTE.mask ||
      this->mask == SECOND.mask ||
      this->mask == MICROSECOND.mask)
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

int SQLIntervalUnit::hashCode() { return mask; };

SQLIntervalUnit_ptr SQLIntervalUnit::valueOf(string_ptr name)
{
  if ("YEAR" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::YEAR));
  }
  else if ("YEAR_MONTH" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::YEAR_MONTH));
  }
  else if ("QUARTER" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::QUARTER));
  }
  else if ("MONTH" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::MONTH));
  }
  else if ("WEEK" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::WEEK));
  }
  else if ("DAY" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY));
  }
  else if ("DAY_HOUR" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_HOUR));
  }
  else if ("DAY_MINUTE" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_MINUTE));
  }
  else if ("DAY_SECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_SECOND));
  }
  else if ("DAY_MICROSECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_MICROSECOND));
  }
  else if ("HOUR" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::HOUR));
  }
  else if ("HOUR_MINUTE" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::HOUR_MINUTE));
  }
  else if ("HOUR_SECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::HOUR_SECOND));
  }
  else if ("HOUR_MICROSECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::HOUR_MICROSECOND));
  }
  else if ("MINUTE" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::MINUTE));
  }
  else if ("MINUTE_SECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::MINUTE_SECOND));
  }
  else if ("MINUTE_MICROSECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::MINUTE_MICROSECOND));
  }
  else if ("SECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::SECOND));
  }
  else if ("SECOND_MICROSECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::SECOND_MICROSECOND));
  }
  else if ("MICROSECOND" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::MICROSECOND));
  }
  else if ("DAY_OF_WEEK" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_OF_WEEK));
  }
  else if ("DOW" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DOW));
  }
  else if ("DAY_OF_MONTH" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_OF_MONTH));
  }
  else if ("DAY_OF_YEAR" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DAY_OF_YEAR));
  }
  else if ("YEAR_OF_WEEK" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::YEAR_OF_WEEK));
  }
  else if ("YOW" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::YOW));
  }
  else if ("TIMEZONE_HOUR" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::TIMEZONE_HOUR));
  }
  else if ("TIMEZONE_MINUTE" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::TIMEZONE_MINUTE));
  }
  else if ("DOY" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::DOY));
  }
  else if ("YEAR_TO_MONTH" == *name)
  {
    return SQLIntervalUnit_ptr(new SQLIntervalUnit(&SQLIntervalUnit::YEAR_TO_MONTH));
  }
}

BOOL_ptr SQLIntervalUnit::operator==(SQLIntervalUnit &rgt)
{
  return (name == rgt.name && mask == rgt.mask)?BOOL::TRUE:BOOL::FALSE;
}